﻿using System;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media.Imaging;
using GpgApi;
using Microsoft.Win32;
using WgpgCore;

namespace WgpgGUI
{
    public partial class DialogKeyInformation : Window, INotifyPropertyChanged
    {
        private Boolean m_busy;
        private Int32 m_photoindex = 0;

        public KeyNode KeyNode { get; private set; }
        public BitmapSource DisplayedPhoto { get; private set; }

        public DialogKeyInformation(Window owner, KeyId keyid)
        {
            m_busy = true;

            KeyNode = KeyManager.GetKeyNodeById(keyid);
            DisplayedPhoto = null;

            DataContext = this;

            Owner = owner;
            InitializeComponent();
            DisplayKey();
            Focus();        // See http://cebla5.spaces.live.com/blog/cns!1B8262ED00250003!206.entry?wa=wsignin1.0&sa=834175698 for more information

            KeyManager.Keys.CollectionChanged += Keys_CollectionChanged;

            m_busy = false;
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String name)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(name));
        }

        public void Keys_CollectionChanged(Object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Remove)
            {
                IList list = e.OldItems;
                foreach (KeyNode keynode in list)
                {
                    if (keynode.Id == KeyNode.Id)
                    {
                        Close();
                        return;
                    }
                }
            }
        }

        protected override void OnClosed(EventArgs e)
        {
            BindingOperations.ClearAllBindings(this);
            KeyManager.Keys.CollectionChanged -= Keys_CollectionChanged;
            base.OnClosed(e);
        }

        private void RefreshKey()
        {
            m_busy = true;

            KeyManager.RefreshKey(KeyNode.Id);
            DisplayKey();

            m_busy = false;
        }

        private void DisplayKey()
        {
            UpdatePhoto();

            combo_names.SelectedIndex = 0;

            switch (KeyNode.OwnerTrust)
            {
                case KeyOwnerTrust.Ultimate:
                    combo_ownertrust.SelectedIndex = 0;
                    break;
                case KeyOwnerTrust.Full:
                    combo_ownertrust.SelectedIndex = 1;
                    break;
                case KeyOwnerTrust.Marginal:
                    combo_ownertrust.SelectedIndex = 2;
                    break;
                default:
                    combo_ownertrust.SelectedIndex = 3;
                    break;
            }

            if (KeyNode.Type == KeyType.Public)
            {
                image_photo.AllowDrop = false;
                PhotoButtons.Visibility = Visibility.Collapsed;
                password_button.Visibility = Visibility.Collapsed;
                image_menu.Visibility = Visibility.Collapsed;
                btnPrimary.Visibility = Visibility.Collapsed;
                btnAddIdentity.Visibility = Visibility.Collapsed;
                btnRemoveIdentity.Visibility = Visibility.Collapsed;
            }
        }

        private void DragEnterImage(Object sender, DragEventArgs e)
        {
            e.Handled = true;
            e.Effects = Photo.IsValidDrop(e) ? DragDropEffects.Copy : DragDropEffects.None;
        }

        private void DropImage(Object sender, DragEventArgs e)
        {
            e.Handled = true;

            if (Photo.Add(this, e, KeyNode.Id))
            {
                e.Effects = DragDropEffects.Copy;
                RefreshKey();
            }
            else
                e.Effects = DragDropEffects.None;
        }

        private void AddPhoto(Object sender, RoutedEventArgs e)
        {
            const String filters = "{0}|*.*|"
                                 + "{1}|*.jpg;*.png;*.gif|"
                                 + "{2}|*.jpg;*.jpeg|"
                                 + "{3}|*.png|"
                                 + "{4}|*.gif";                    

            OpenFileDialog dialog = new OpenFileDialog
            {
                Title = L10N.T("dialog_choose_a_photo_title"),
                Multiselect = false,
                CheckFileExists = true,
                CheckPathExists = true,
                Filter = String.Format(filters, L10N.T("filter_allfiles"), L10N.T("filter_allimages"), L10N.T("filter_jpgimages"), L10N.T("filter_pngimages"), L10N.T("filter_gifimages")),
                FilterIndex = 2
            };

            if (dialog.ShowDialog(this) != true)
                return;

            if (Photo.Add(this, dialog.FileName, KeyNode.Id))
                RefreshKey();
        }

        private void RemovePhoto(Object sender, RoutedEventArgs e)
        {
            if (CustomMessageBox.Show(this, L10N.T("removephoto_content"), L10N.T("removephoto_title"), MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No, null, L10N.T("button_remove"), L10N.T("button_cancel"), null, MessageBoxResult.No) != MessageBoxResult.Yes)
                return;

            KeyPhotoNode photo = KeyNode.Photos[m_photoindex];

            GpgDeleteUserId delete = new GpgDeleteUserId(photo.Key.Id, photo.Index);
            delete.ExecuteAsync(result => RefreshKey());
        }

        private void PreviousPhoto(Object sender, RoutedEventArgs e)
        {
            m_photoindex--;
            UpdatePhoto();
        }

        private void NextPhoto(Object sender, RoutedEventArgs e)
        {
            m_photoindex++;
            UpdatePhoto();
        }

        private void UpdatePhoto()
        {
            if (KeyNode.Photos.Count == 0)
            {
                no_image_photo.Visibility = Visibility.Visible;
                image_photo.Visibility = Visibility.Collapsed;
                remove_button.IsEnabled = false;

                m_photoindex = 0;
                previous_photo_button.Visibility = Visibility.Collapsed;
                next_photo_button.Visibility = Visibility.Collapsed;
            }
            else
            {
                no_image_photo.Visibility = Visibility.Collapsed;
                image_photo.Visibility = Visibility.Visible;
                remove_button.IsEnabled = true;

                m_photoindex = Math.Min(KeyNode.Photos.Count - 1, Math.Max(0, m_photoindex));
                previous_photo_button.Visibility = m_photoindex == 0 ? Visibility.Collapsed : Visibility.Visible;
                next_photo_button.Visibility = m_photoindex == KeyNode.Photos.Count - 1 ? Visibility.Collapsed : Visibility.Visible;

                DisplayedPhoto = Photo.ImageToBitmapSource(KeyNode.Photos[m_photoindex].Image);
                NotifyPropertyChanged("DisplayedPhoto");
            }
        }

        private void ChangePassword(Object sender, RoutedEventArgs e)
        {
            GpgChangePassword changepassword = new GpgChangePassword(KeyNode.Id)
            {
                AskPassphrase = GUIUtils.AskPassphrase(this)
            };

            GpgInterfaceResult result = changepassword.Execute();
            if (result.Status == GpgInterfaceStatus.Error && result.Message == GpgInterfaceMessage.BadPassphrase)
                CustomMessageBox.Show(this, L10N.T("bad_passphrase"), L10N.T("bad_passphrase_title"), MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK);
        }

        private void ChangeDisable(Object sender, SelectionChangedEventArgs e)
        {
            if (m_busy)
                return;

            GpgChangeDisable changedisable = new GpgChangeDisable(KeyNode.Id, combo_disabled.SelectedIndex == 0);
            changedisable.ExecuteAsync(result => RefreshKey());
        }

        private void ChangeTrust(Object sender, SelectionChangedEventArgs e)
        {
            if (m_busy)
                return;

            KeyOwnerTrust otrust;
            switch (combo_ownertrust.SelectedIndex)
            {
                case 0:
                    otrust = KeyOwnerTrust.Ultimate;
                    break;
                case 1:
                    otrust = KeyOwnerTrust.Full;
                    break;
                case 2:
                    otrust = KeyOwnerTrust.Marginal;
                    break;
                default:
                    otrust = KeyOwnerTrust.None;
                    break;
            }

            GpgChangeOwnerTrust changeownertrust = new GpgChangeOwnerTrust(KeyNode.Id, otrust);
            changeownertrust.ExecuteAsync(result => RefreshKey());
        }

        public static RoutedCommand PasteImageCommand = new RoutedCommand();
        public static RoutedCommand AddUserIdentityCommand = new RoutedCommand();
        public static RoutedCommand RemoveUserIdentityCommand = new RoutedCommand();
        public static RoutedCommand ChangePrimaryIdentityCommand = new RoutedCommand();

        #region Command: Paste Image
        private void PasteImage_CanExecute(Object sender, CanExecuteRoutedEventArgs e)
        {
            e.Handled = true;
            e.CanExecute = Clipboard.ContainsImage();
        }

        private void PasteImage_Executed(Object sender, ExecutedRoutedEventArgs e)
        {
            e.Handled = true;
            if (Photo.Add(this, Clipboard.GetImage(), KeyNode.Id))
                RefreshKey();
        }
        #endregion Command: Paste Image

        #region Command: Add User Identity
        private void AddUserIdentifiant_CanExecute(Object sender, CanExecuteRoutedEventArgs e)
        {
            e.Handled = true;
            e.CanExecute = true;
        }

        private void AddUserIdentifiant_Executed(Object sender, ExecutedRoutedEventArgs e)
        {
            e.Handled = true;

            DialogAddIdentification add = new DialogAddIdentification(this);
            if (add.ShowDialog() != true)
                return;

            GpgAddUserInfo adduserinfo = new GpgAddUserInfo(KeyNode.Id, add.FullName, add.Email, add.Comment)
            {
                AskPassphrase = GUIUtils.AskPassphrase(this)
            };

            adduserinfo.ExecuteAsync(result =>
            {
                if (result.Status == GpgInterfaceStatus.Success)
                    RefreshKey();
            });
        }
        #endregion Command: Add User Identity

        #region Command: Remove User Identity
        private void RemoveUserIdentifiant_CanExecute(Object sender, CanExecuteRoutedEventArgs e)
        {
            e.Handled = true;
            e.CanExecute = KeyNode.Type == KeyType.Pair && KeyNode.UserInfos != null && KeyNode.UserInfos.Count > 1;
        }

        private void RemoveUserIdentifiant_Executed(Object sender, ExecutedRoutedEventArgs e)
        {
            e.Handled = true;

            if (KeyNode.Type != KeyType.Pair)
                return;

            MessageBoxResult res = CustomMessageBox.Show(this, L10N.T("dialogremoveidentity_content"), L10N.T("dialogremoveidentity_title"), MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No, null, L10N.T("button_remove"), L10N.T("button_cancel"), null, MessageBoxResult.No);
            if (res != MessageBoxResult.Yes)
                return;

            KeyUserInfoNode node = combo_names.SelectedItem as KeyUserInfoNode;
            GpgDeleteUserId del = new GpgDeleteUserId(KeyNode.Id, node.Index)
            {
                AskPassphrase = GUIUtils.AskPassphrase(this)
            };

            del.ExecuteAsync(result =>
            {
                if (result.Status == GpgInterfaceStatus.Success)
                    RefreshKey();
            });
        }
        #endregion Command: Remove User Identity

        #region Command: Change Primary Identity
        private void ChangePrimaryIdentifiant_CanExecute(Object sender, CanExecuteRoutedEventArgs e)
        {
            e.Handled = true;
            e.CanExecute = combo_names != null && combo_names.SelectedIndex != 0;
        }

        private void ChangePrimaryIdentifiant_Executed(Object sender, ExecutedRoutedEventArgs e)
        {
            e.Handled = true;

            if (combo_names.SelectedIndex == 0)
                return;

            KeyUserInfoNode node = combo_names.SelectedItem as KeyUserInfoNode;

            GpgChangePrimaryUserInfo changeuserinfo = new GpgChangePrimaryUserInfo(KeyNode.Id, node.Index)
            {
                AskPassphrase = GUIUtils.AskPassphrase(this)
            };

            changeuserinfo.ExecuteAsync(result =>
            {
                if (result.Status == GpgInterfaceStatus.Success)
                    RefreshKey();
            });
        }
        #endregion Command: Change Primary Identity
    }
}
